/****************************************************************************

	COPYRIGHT(C) MAXSI SOFTWARE, JONAS 'SORTIE' TERMANSEN 2008, 2009, 2010

    This file is part of Maxsi ImaginationLand.

    Maxsi ImaginationLand is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Maxsi ImaginationLand is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Maxsi ImaginationLand.  If not, see <http://www.gnu.org/licenses/>.

	*/ #include "MaxsiImaginationLandContributors.h" /*

	If you modify this file, please enter your name below and provide contact
	information in MaxsiImaginationLandContributors.h. For more information please see
	MaxsiImaginationLandContributors.h.
	
	Contributors to this file:

	- Jonas 'Sortie' Termansen
	- [your name here]


	MaxsiImaginationLand.exe
	Imaginary programming!
	
	Graph.cpp
	A >SIMPLE< way to make real pretty graphs!

****************************************************************************/

#include "MaxsiEngine.h"
#include <math.h>
#include <io.h>
#include <direct.h>
#include <iostream> 
#include <fcntl.h>
#include <SYS\Stat.h>
#include "Main.h"

#ifdef GOSH_WHY_DOESNT_THERE_EXIST_SOME_SIMPLE_GRAPH_SOFTWARE

double YFunc(double X)
{
	return (-3.0f*X*X-3.0f)/(2.0f*X);
}

double XMin()
{
	return -5.0f;
}

double XMax()
{
	return 5.0f;
}

double YMin()
{
	return -10.0f;
}

double YMax()
{
	return 10.0f;
}

COLORREF*			Buffer1			=	NULL;
COLORREF*			Buffer2			=	NULL;
COLORREF*			FrontBuffer		=	NULL;
COLORREF*			BackBuffer		=	NULL;
DWORD_PTR			nThreads		=	0;
HANDLE				DrawEvent		=	NULL;
HANDLE				DrawedEvent		=	NULL;
HANDLE*				Thread			=	NULL;
HANDLE*				ThreadDone		=	NULL;
RECT				rectClient;

ME_WIN32ENTRYPOINT(MaxsiImaginationLand);

/****************************************************************************

    FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
    PURPOSE: calls initialization function, processes message loop

****************************************************************************/

int WINAPI MaxsiImaginationLand::WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
	//BenchMarkZ();
	//TestSlowInvSqrt();
	//TestFastInvSqrt();
		
	nThreads	=	GetNumberOfLogicalCPUs();
	
	return BaseClass::WinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);
}


/****************************************************************************

    FUNCTION: InitApplication(HANDLE)
    PURPOSE: Initializes window data and registers window class

****************************************************************************/

BOOL MaxsiImaginationLand::InitApplication(
    HANDLE hInstance)
{
    WNDCLASS  wc = {0};

    wc.lpfnWndProc = (WNDPROC) MaxsiImaginationLandProc;
    wc.hInstance = (HINSTANCE)hInstance;
    wc.hIcon = LoadIconA((HINSTANCE)hInstance, "ProductIcon");
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wc.lpszClassName = TEXT("MaxsiImaginationLand");

	if (!RegisterClass(&wc)) { return FALSE; }

	return TRUE;
}


/****************************************************************************

    FUNCTION:  InitInstance(HANDLE, int)
    PURPOSE:  Saves instance handle and creates main window

****************************************************************************/
BOOL MaxsiImaginationLand::InitInstance(
    HINSTANCE hInstance, 
    INT nCmdShow)
{
	//nCmdShow	=	SW_SHOWMAXIMIZED;

    LPTSTR lpszText = NULL;
    BOOL bSuccess = TRUE;

    hInst = hInstance;

    hAccTable = LoadAccelerators(hInst, TEXT("MaxsiImaginationLand"));

	// Get the screen size
	DEVMODE Dev;
	BOOL	Result	=	EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&Dev);
	//int w = Dev.dmPelsWidth;
	//int h = Dev.dmPelsHeight;
	int w = 800;
	int h = 600;
	int x = (Result) ? (int)(Dev.dmPelsWidth - w ) / 2 : (int)CW_USEDEFAULT;
	int y = (Result) ? (int)(Dev.dmPelsHeight - h ) / 2 : (int)CW_USEDEFAULT;

	char*	WindowTitle		=	BuildString(1,"Maxsi ImaginationLand");

    WindowHWND = CreateWindowA(
        "MaxsiImaginationLand",
        WindowTitle,
        (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX ),
        x, y,
        w, h,
        NULL, NULL, hInstance, NULL );

	delete[] WindowTitle;

	if (!WindowHWND) { return FALSE; }


	ME_Window*	Parent	=	ME_WindowGetPointer(WindowHWND);

	ShowWindow(WindowHWND, nCmdShow);
    bSuccess = UpdateWindow(WindowHWND);

	return bSuccess;
}

/****************************************************************************

    FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
    PURPOSE:  Processes messages

****************************************************************************/

LRESULT APIENTRY MaxsiImaginationLand::WindowProc(
    HWND hWnd, 
    UINT message, 
    WPARAM wParam, 
    LPARAM lParam)
{
	switch (message) 
	{
			case WM_PAINT:
				Imagine();
				break;

		default:			
			return (BaseClass::WindowProc(hWnd, message, wParam, lParam));
	}
	return (0);

	return BaseClass::WindowProc(hWnd,message,wParam,lParam);
}


DWORD MaxsiImaginationLand::OnThreadRegistered(HWND hWnd)
{
	PostMessage(hWnd,WM_COMMAND,0,0);

	return BaseClass::OnThreadRegistered(hWnd);
}

void Imagine()
{	
	HWND	hWnd	=	Application.WindowHWND;

    PAINTSTRUCT ps          = {0};
	HDC hDC = BeginPaint (hWnd, &ps);

    GetClientRect (hWnd, &rectClient);

	if ( Buffer1 == NULL ) { Buffer1 = new COLORREF[rectClient.bottom*rectClient.right]; }

	COLORREF	White	=	RGB(255,255,255);

	// Draw

	BackBuffer	=	Buffer1;

	// Draw->Clear

	size_t Area = rectClient.bottom*rectClient.right;

	for ( size_t I = 0; I < Area; I++ )
	{
		BackBuffer[I]	=	White;
	}

	// Draw_>Draw the grid!

	LONG	iL		=	0;
	LONG	iT		=	0;
	LONG	iR		=	rectClient.right-0;
	LONG	iB		=	rectClient.bottom-0;
	LONG	iW		=	iR-iL;
	LONG	iH		=	iB-iT;
	double	W		=	(double)rectClient.right;
	double	H		=	(double)rectClient.bottom;
	double ScaleX	=	W/(XMax()-XMin());
	double ScaleY	=	H/(YMax()-YMin());
	int LastN		=	-1;

	int GridX		=	(int)W-(ScaleX*(-XMin()));
	int GridY		=	(int)H-(ScaleY*(-YMin()));

	for ( int I = iL; I < iR; I++ )
	{
		BackBuffer[GridY*rectClient.right+I]	=	0;
	}
	for ( int I = iT; I < iB; I++ )
	{
		BackBuffer[I*rectClient.right+GridX]	=	0;
	}

	// Draw->Draw The Actual Graph


	for ( size_t I = 0; I < iW; I++ )
	{
		// ... LE~ERP!
		double X	=	XMax()*((double)I/W)+XMin()*(1-(double)I/W);
		double Y	=	YFunc(X);

		// Now translate Y to screen coordinates!
		// ScreenY(YMin()) = rectClient.bottom;
		// ScreenY(YMax()) = 0;
		double SY	=	H-(ScaleY*(Y-YMin()));

		int N	=	(int)SY;

		if ( LastN == -1 )
		{
			LastN = N;
		}

		if ( N >=iT && N <= iH )
		{
			if ( LastN != N )
			{
				while ( LastN != N )
				{
					if ( LastN > N ) { LastN--; } 
					if ( LastN < N ) { LastN++; } 

					if ( LastN <= (iT+iH) && LastN >= iT)
					{
						BackBuffer[(LastN+iT)*rectClient.right+I+iL]	=	255*256*256;
					}
				}
			}
			else
			{
				if ( (size_t)LastN <= rectClient.bottom )
				{
					BackBuffer[(LastN+iT)*rectClient.right+I+iL]	=	255*256*256;
				}
			}
			LastN = N;
		}
		else
		{
			LastN = -1;
		}

	}

	// Render
		
	HBITMAP		DrawBackBuffer	=	CreateCompatibleBitmap(hDC, rectClient.right, rectClient.bottom);

	BITMAPINFO	DrawBackBufferInfo;
	DrawBackBufferInfo.bmiHeader.biBitCount = 32;
	DrawBackBufferInfo.bmiHeader.biClrImportant = 0;
	DrawBackBufferInfo.bmiHeader.biClrUsed = 0;
	DrawBackBufferInfo.bmiHeader.biCompression = BI_RGB;
	DrawBackBufferInfo.bmiHeader.biHeight = 0-rectClient.bottom;
	DrawBackBufferInfo.bmiHeader.biPlanes = 1;
	DrawBackBufferInfo.bmiHeader.biSize = sizeof(DrawBackBufferInfo);
	DrawBackBufferInfo.bmiHeader.biSizeImage = BI_RGB;
	DrawBackBufferInfo.bmiHeader.biWidth = rectClient.right;
	DrawBackBufferInfo.bmiHeader.biXPelsPerMeter = 0;
	DrawBackBufferInfo.bmiHeader.biYPelsPerMeter = 0;

	SetDIBits(hDC,DrawBackBuffer,0,rectClient.bottom,BackBuffer,&DrawBackBufferInfo, DIB_RGB_COLORS );

	BITMAP    Bitmap;

	HDC hDCBits = CreateCompatibleDC(hDC);
	GetObject(DrawBackBuffer, sizeof(BITMAP), (LPSTR)&Bitmap);
	SelectObject(hDCBits, DrawBackBuffer);
	BitBlt(hDC, 0, 0, rectClient.right, rectClient.bottom, hDCBits, 0, 0, SRCCOPY);
	DeleteDC(hDCBits);

	DeleteObject(BackBuffer);

    EndPaint (hWnd, &ps);
}

#endif